package com.company.project.utils;

/**
 * @Description: 描述内容
 * @Author: sunqiang
 * @CreateDate: 2019/12/16  13:18
 * @UpdateUser: sunqiang
 * @UpdateDate: 2019/12/16  13:18
 * @UpdateRemark: 修改内容
 * @Version: 1.0
 */

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.math.BigDecimal;
import java.util.*;

import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

/**
 * xml/map转换工具类
 */
public class XmlMapUtil {

    public static final char UNDERLINE_CHAR = '_';


    /**
     * xml字符串转map
     *
     * @param xml
     * @return
     */
    public static Map<String, Object> xml2map(String xml) {
        Document doc = null;
        try {
            //将xml字符串转为document对象
            doc = DocumentHelper.parseText(xml);
        } catch (DocumentException e) {
            System.out.println(e.getMessage());
        }
        Map<String, Object> map = new HashMap<>();
        if (doc == null) {
            return map;
        } else {
            //获取根节点
            Element rootElement = doc.getRootElement();
            element2map(rootElement, map);
        }
        return map;
    }

    /**
     * map转xml字符串
     *
     * @param map
     * @return
     */
    public static String map2xml(Map<String, Object> map, String rootElement) {
        StringBuffer xmlStr = new StringBuffer("");
        if (map.isEmpty())
            return xmlStr.toString();
        xmlStr.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><" + rootElement + ">");
        map2Element(map, xmlStr);
        xmlStr.append("</" + rootElement + ">");
        return xmlStr.toString();
    }

    /**
     * 递归原则 : 一个map对应一个xml节点,key为当前xml节点名,value为当前xml节点子集
     * 如果xml节点没有子节点(叶子节点),那么map的key为xml节点名,value为xml节点文本内容
     * 如果xml节点有一个子节点,那么map的key为xml节点名,value为xml节点子集
     * 如果xml节点有多个子节点,对应map的key不存在(每一次),map的key为xml节点名,value为xml节点子集
     * 如果xml节点有多个子节点,对应map的key已存在,且value为map类型(第二次),map的key为xml节点名,值从map类型转为list,而list中添加2份当前xml节点子集
     * 如果xml节点有多个子节点,对应map的key已存在,且value为list类型(第三/多次),那么直接加到list中去.
     *
     * @param elmt
     * @param map
     * @see [类、类#方法、类#成员]
     */
    @SuppressWarnings("unchecked")
    private static void element2map(Element elmt, Map<String, Object> map) {
        if (null == elmt) {
            return;
        }
        String name = elmt.getName();

        //判断当前节点的内容是否为文本（最里面一层节点）
        if (elmt.isTextOnly()) {
            map.put(name, elmt.getText());
        } else {
            Map<String, Object> mapSub = new HashMap<>();

            //获取当前节点的所有子节点
            List<Element> elements = (List<Element>) elmt.elements();

            //利用递归获取节点值
            for (Element elmtSub : elements) {
                element2map(elmtSub, mapSub);
            }
            Object first = map.get(name);

            //判断
            if (null == first) {
                map.put(name, mapSub);
            } else {
                if (first instanceof List<?>) {
                    ((List<Map<String, Object>>) first).add(mapSub);
                } else {
                    List<Object> listSub = new ArrayList<Object>();
                    listSub.add(first);
                    listSub.add(mapSub);
                    map.put(name, listSub);
                }
            }
        }
    }

    /**
     * 递归map转xml字符串
     *
     * @param map
     * @param sb
     */
    @SuppressWarnings("unchecked")
    private static void map2Element(Map<String, Object> map, StringBuffer sb) {
        Set<String> set = map.keySet();
        for (Iterator<String> it = set.iterator(); it.hasNext(); ) {
            String key = (String) it.next();
            Object value = map.get(key);
            if (null == value)
                value = "";
            if (value instanceof List<?>) {
                List<Object> list = (List<Object>) map.get(key);
                sb.append("<" + key + ">");
                for (int i = 0; i < list.size(); i++) {
                    Map<String, Object> hm = (Map<String, Object>) list.get(i);
                    map2Element(hm, sb);
                }
                sb.append("</" + key + ">");
            } else {
                if (value instanceof Map<?, ?>) {
                    sb.append("<" + key + ">");
                    map2Element((Map<String, Object>) value, sb);
                    sb.append("</" + key + ">");
                } else {
                    sb.append("<" + key + ">" + value + "</" + key + ">");
                }

            }
        }
    }


    //将map通过反射转化为实体
    public static Object mapToModel(Map<String, Object> map, Object o) throws Exception {
        if (!map.isEmpty()) {
            for (String k : map.keySet()) {
//                System.out.println(k);
                Object v = null;
                if (!k.isEmpty()) {
                    v = map.get(k);
                }
                //object没有被继承，单层object的所有字段
//                Field[] fields = null;
//                fields = o.getClass().getDeclaredFields();
//                System.out.println(v);
                //得到field的为全类型字段名，如：private java.lang.String com.ylztdy.entity.OutpPrescMrec.patregNo
                List<Field> fields = new ArrayList<>();
                Class tempClass = o.getClass();
                //当父类为null的时候说明到达了最上层的父类(Object类)，有继承的object
                while (tempClass != null && !tempClass.getName().toLowerCase().equals("java.lang.object")) {
                    fields.addAll(Arrays.asList(tempClass.getDeclaredFields()));
                    tempClass = tempClass.getSuperclass(); //得到父类,然后赋给自己
                }
                try {
                    for (Field field : fields) {
                        String fieldName = camel2Underline(field.getName());
                        if (fieldName.toUpperCase().equals(k.toUpperCase())) {
                            field.setAccessible(true);
                            //region--进行类型判断，type：class java.lang.String
                            String type = field.getType().toString();
//                            System.out.println("type:" + type);
                            if (type.endsWith("String")) {
                                if (v == null) {
                                    v = "";
                                } else {
                                    v = v.toString();
                                }
                            }
                            if (type.endsWith("Date")) {
                                if (v == null) {
                                    v = null;
                                } else {

//                                    if ((field.getAnnotation(ClassType.class) != null) && field.getAnnotation(ClassType.class).isNull()) {
//                                        v = DateUtils.strToDateTime(v.toString());
//                                    } else {
//                                        if (v.toString().length() != "yyyyMMddHHmmss".length()) {
////                                            if (v.toString().length() == 28) {
////                                                continue;
////                                            }
//                                            String result = JsonXmlUtils.getResponseFailMessage(fieldName + "传入的日期格式必须为yyyyMMddHHmmss" + ",值为" + v.toString());
//                                            throw new Exception(result);
//                                        }
//                                        v = DateUtils.strToDateTime(v.toString());
//                                    }
//
                                }
                            }

                            if (type.endsWith("Boolean")) {
                                if (v == null) {
                                    v = null;
                                } else {
                                    v = Boolean.getBoolean(v.toString());
                                }
                            }
                            if (type.endsWith("int") || type.endsWith("Integer")) {
                                if (v == null || v.equals("")) {
                                    v = null;
                                } else {
                                    v = new Integer(v.toString());
                                }
                            }
                            if (type.endsWith("Long")) {
                                if (v == null || v.equals("")) {
                                    v = null;
                                } else {
                                    v = new Long(v.toString());
                                }
                            }
                            if (type.endsWith("Short")) {
                                if (v == null || v.equals("")) {
                                    v = null;
                                } else {
                                    v = new Short(v.toString());
                                }
                            }
                            if (type.endsWith("BigDecimal")) {
                                if (v == null || v.equals("")) {
                                    v = null;
                                } else {
                                    v = new BigDecimal(v.toString());
                                }
                            }
                            if (type.endsWith("List")) {
                                Map sMap = (Map) v;
                                Set value = sMap.keySet();
                                List slist = null;
                                //判断map中key是不是唯一的，唯一后可能存在value是集合
                                if (value.size() == 1) {
                                    if (sMap.get(value.toArray()[0]).getClass().toString().endsWith("Map")) {
                                        slist = new ArrayList();
                                        slist.add(sMap.get(value.toArray()[0]));
                                    } else {
                                        slist = (List) sMap.get(value.toArray()[0]);
                                    }

                                } else {
                                    continue;
                                }
                                JSONArray array = JSONArray.parseArray(JSON.toJSONString(slist));
                                //先获取List的类型：java.util.List<E>
                                ParameterizedType pt = (ParameterizedType) field.getGenericType();
                                //获取泛型：E
                                Class e = (Class) pt.getActualTypeArguments()[0];
                                List list = JSONArray.parseArray(array.toJSONString(), e);
                                v = list;
                            }
                            field.set(o, v);
                        }
                    }
                } catch (Exception e) {
                    System.out.println(e);
//                    String result = JsonXmlUtils.getResponseFailMessage(k + " 类型转换失败" + ",值为" + v.toString() + " 错误信息:" + e.toString());
                    throw new Exception(e.toString());
                }
            }
        }
        return o;
    }


    /**
     * 驼峰转下划线
     *
     * @param camelStr
     * @return
     */
    public static String camel2Underline(String camelStr) {

        if (StringUtils.isEmpty(camelStr)) {

            return null;
        }

        int len = camelStr.length();
        StringBuilder strb = new StringBuilder(len + len >> 1);
        for (int i = 0; i < len; i++) {

            char c = camelStr.charAt(i);
            if (Character.isUpperCase(c)) {

                strb.append(UNDERLINE_CHAR);
                strb.append(Character.toLowerCase(c));
            } else {

                strb.append(c);
            }
        }
        return strb.toString();
    }

    /***
     * 下划线命名转为驼峰命名.
     *
     * @param para 下划线命名的字符串
     */
    public static String underlineToHump(String para) {
        if (org.apache.commons.lang3.StringUtils.isBlank(para)) {
            return para;
        }
        para = para.toLowerCase();
        StringBuilder result = new StringBuilder();
        String[] a = para.split("_");
        if (a.length != 1) {
            for (String s : a) {
                if (result.length() == 0) {
                    result.append(s.toLowerCase());
                } else {
                    result.append(s.substring(0, 1).toUpperCase());
                    result.append(s.substring(1).toLowerCase());
                }
            }
        } else {
            result.append(a[0].substring(0, 1).toLowerCase());
            result.append(a[0].substring(1));
        }
        return result.toString();
    }

    /**
     * 蛇形转驼峰.
     *
     * @param map map里面的key为蛇形
     * @return newMap newMap里面的key为驼峰
     */
    public static Map<String, Object> convertToHump(Map<String, Object> map) {
        Map<String, Object> returnMap = new HashMap<>();
        for (Map.Entry<String, Object> data : map.entrySet()) {
            String key = underlineToHump(data.getKey());
            returnMap.put(key, data.getValue());
        }
        return returnMap;
    }

    /**
     * 蛇形转驼峰.
     *
     * @param datas
     * @return
     */
    public static List<Map<String, Object>> underlineToHumpList(List<Map<String, Object>> datas) {
        List<Map<String, Object>> tempDatas = new ArrayList<Map<String, Object>>(datas.size());
        for (Map<String, Object> map : datas) {
            tempDatas.add(convertToHump(map));
        }
        return tempDatas;
    }

    public static void main(String[] args) throws Exception {
        String result = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
                "<getRegisterList ITSVersion=\"XML_1.0\" xmlns=\"urn:hl7-org:v3\"\n" +
                "                 xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
                "                 xsi:schemaLocation=\"urn:hl7-org:v3\">\n" +
                "    <creationTime value=\"20180925192804\"/>\n" +
                "    <interactionId root=\"2.16.840.1.113883.1.6\" extension=\"CFLZ\"/>\n" +
                "    <processingCode code=\"P\"/>\n" +
                "    <processingModeCode code=\"I\"/>\n" +
                "    <!--typeCode 为处理结果，AA 表示成功 AE 表示失败-->\n" +
                "    <acknowledgement typeCode=\"AA\">\n" +
                "        <acknowledgementDetail>\n" +
                "            <!--处理结果说明-->\n" +
                "            <text>c</text>\n" +
                "        </acknowledgementDetail>\n" +
                "    </acknowledgement>\n" +
                "    <dataSet>\n" +
                "        <dataRow>\n" +
                "            <JIAGEID> 22127</JIAGEID>\n" +
                "            <JIUZHENID> 120951349</JIUZHENID>\n" +
                "            <JIESUANJE> 2,796</JIESUANJE>\n" +
                "            <SHULIANG> 4</SHULIANG>\n" +
                "            <JIESUANJIA> 699</JIESUANJIA>\n" +
                "        </dataRow>\n" +
                "        <dataRow>\n" +
                "            <JIAGEID> 22128</JIAGEID>\n" +
                "            <JIUZHENID> 120951349</JIUZHENID>\n" +
                "            <JIESUANJE> 2,796</JIESUANJE>\n" +
                "            <SHULIANG> 4</SHULIANG>\n" +
                "            <JIESUANJIA> 699</JIESUANJIA>\n" +
                "        </dataRow>\n" +
                "    </dataSet>\n" +
                "</getRegisterList>";

        Map<String, Object> map = xml2map(result);
        System.out.println(map);

    }

}
